package com.conncui.common.classoperate;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MyClassLoader extends ClassLoader {

    List<String> dirList = new ArrayList<>();
    HashMap<String, Class> classMap = new HashMap();

    @Override
    public Class<?> findClass(String name) {
        Class clazz = classMap.get(name);
        if (clazz == null) {
            clazz = findClassInDir(name);
            classMap.put(name, clazz);
        }
        System.out.println(name + " findClass " + clazz.getCanonicalName());
        return clazz;
    }

    @SuppressWarnings("NewApi")
    private Class<?> findClassInDir(String name) {
        String classPath = findClassPathInDir(name);
        if (classPath == null) {
            return null;
        }
//        String classPath = "file:///Users/cuiguoqiang/work/oschina/AndroidProject/ConnCommonAndroid/build/intermediates/classes/test/debug_2/" + name.replace(".","/") + ".class";
//        System.out.println(classPath);

        byte[] cLassBytes = null;
        Path path = null;
        try {
            path = Paths.get(new File(classPath).toURI());
            cLassBytes = Files.readAllBytes(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Class clazz = defineClass(name, cLassBytes, 0, cLassBytes.length);
        return clazz;
    }

    private String findClassPathInDir(final String name) {
        String packageName = name.substring(0, name.lastIndexOf("."));
        final String classSimpleName = name.substring(name.lastIndexOf(".") + 1);

        String packagePath = packageName.replace('.', File.separatorChar);

        File file;
        for (String dir : dirList) {
            file = new File(dir + File.separatorChar + packagePath);
            System.out.println(file.getAbsolutePath() + " exists -> " + file.exists());

            System.out.println("classSimpleName: " + classSimpleName);
            String[] targetClass = file.list(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String fileName) {
                    System.out.println("has file: " + fileName);
                    if (fileName.endsWith(".class")) {
                        if (classSimpleName.equals(fileName.substring(0, fileName.lastIndexOf(".")))) {
                            return true;
                        }
                    }
                    return false;
                }
            });
            if (targetClass.length > 0) {
                return dir + File.separatorChar + packagePath + File.separatorChar + classSimpleName + ".class";
            }
        }
        return null;
    }

    public List<String> getDirList() {
        return dirList;
    }

    public void setDirList(List<String> dirList) {
        this.dirList = dirList;
    }
}